import java.util.ArrayList;
import java.util.List;

public class Cluster {
    private List<DataPoint> dataPoints;
    private String name;
    private int id;
    private DataPoint center;
    public boolean mergedFlag;
    
    public Cluster(int id, String name, ArrayList<DataPoint> dataPoints) {
    	this.dataPoints = dataPoints;
    	this.id = id;
    	this.name = name;
    }

    public Cluster(int id, String name) {
    	this.dataPoints = new ArrayList<DataPoint>();
    	this.id = id;
    	this.name = name;
    }
    
    public List<DataPoint> getDataPoints() {
		return dataPoints;
	}

	public void setDataPoints(List<DataPoint> dataPoints) {
		this.dataPoints = dataPoints;
	}

	public void addDataPoint(DataPoint dataPoint) {
		this.dataPoints.add(dataPoint);
	}
	
	public String getName() {
		return name;
	}

	public int getId() {
		return id;
	}

	public DataPoint getCenter() {
		return center;
	}

	public void setCenter(DataPoint center) {
		this.center = center;
	}

	/**
	 * @return the distance to the last center
	 */
	public double adjustCenter() {
		double[] attributes = new double[this.getCenter().getDimension()];
		int size = this.getDataPoints().size() + 1;
		// sum all attributes up        
        for(DataPoint dataPoint : this.getDataPoints()) 
        	for(int i = 0; i < dataPoint.getDimension(); i++) 
        		attributes[i] += dataPoint.getAttributes()[i];
        
        for(int i = 0; i < this.getCenter().getDimension(); i++) 
    		attributes[i] += this.getCenter().getAttributes()[i];
        // normalize the values
        // if size = 0, newcenter is the last center
        for(int i = 0; i < attributes.length; i++)
        	attributes[i] *= 1.0/size;

        DataPoint newCenter = new DataPoint(attributes);
        double distanceToLastCenter = newCenter.getEuclideanDistanceTo(this.getCenter());
        this.setCenter(newCenter);
		return distanceToLastCenter;
	}

	public void swapDataPoint(Cluster to, DataPoint dataPoint) {
		if(to != null) {
			dataPoint.setCluster(to);
			to.addDataPoint(dataPoint);
			this.remove(dataPoint);
		}
	}

	private boolean remove(DataPoint dataPoint) {
		return this.getDataPoints().remove(dataPoint);
	}
    
    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder("Cluster No." + this.getId() + " '"+ this.getName() + "' ("+this.getDataPoints().size()+"):: Center:");
        for (int i = 0; i < this.getCenter().getDimension(); i++) {
            stringBuilder.append(i);
            stringBuilder.append("::");
            stringBuilder.append(this.getCenter().getAttributes()[i]);
            stringBuilder.append(" ");
        }
        return stringBuilder.toString();
    }
    
    @Override
    public boolean equals(Object obj){
    	Cluster newCluster = null;
    	if(obj.getClass() == this.getClass())
    		newCluster = (Cluster) obj;
    	if(newCluster != null)
    		if(this.getId() == newCluster.getId())
    			return true;
    	return false;
    }

	public int getSamePoints(Cluster newCluster) {
		int i = 0;
		for(DataPoint dp : this.getDataPoints()) {
			for(DataPoint newDP: newCluster.dataPoints) {
				if(dp.equals(newDP))
					i++;
			}
		}
		return i;
	}
	
}
